﻿using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Reflection;


namespace SpecialServices
{
    //SingleProgamInstance uses a mutex synchronization 

    //object to ensure that only one copy of process is running 

    //at a particular time.  It also allows for UI identification

    // of the intial process by bringing that window to the foreground.



    public class SingleProgramInstance : IDisposable
    {
        public string AssemblyTitle
        {
            get
            {
                object[] attributes = System.Reflection.Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(System.Reflection.AssemblyTitleAttribute), false);
                if (attributes.Length > 0)
                {
                    System.Reflection.AssemblyTitleAttribute titleAttribute = (System.Reflection.AssemblyTitleAttribute)attributes[0];
                    if (titleAttribute.Title != "")
                    {
                        return titleAttribute.Title;
                    }
                }
                return System.IO.Path.GetFileNameWithoutExtension(System.Reflection.Assembly.GetExecutingAssembly().CodeBase);
            }
        }
        
        //Win32 API calls necesary to raise an unowned processs main window
        [DllImport("user32.dll")]
        public static extern IntPtr FindWindow(String sClassName, String sAppName);
        [DllImport("user32.dll")]
        private static extern bool SetForegroundWindow(IntPtr hWnd);
        [DllImport("user32.dll")]
        private static extern bool ShowWindowAsync(IntPtr hWnd, int nCmdShow);
       
        private const int SW_RESTORE = 9;
        private const int SW_SHOW = 5;

        private Mutex _processSync;
        private bool _owned = false;


        public SingleProgramInstance()
        {
            //Initialize a named mutex and attempt to

            // get ownership immediately 

            _processSync = new Mutex(
                true, // desire intial ownership

                Assembly.GetExecutingAssembly().GetName().Name,
                out _owned);
        }

        public SingleProgramInstance(string identifier)
        {
            //Initialize a named mutex and attempt to

            // get ownership immediately.

            //Use an addtional identifier to lower

            // our chances of another process creating

            // a mutex with the same name.

            _processSync = new Mutex(
                true, // desire intial ownership

                Assembly.GetExecutingAssembly().GetName().Name + identifier,
                out _owned);
        }

        ~SingleProgramInstance()
        {
            //Release mutex (if necessary) 

            //This should have been accomplished using Dispose() 

            Release();
        }

        public bool IsSingleInstance
        {
            //If we don't own the mutex than

            // we are not the first instance.

            get { return _owned; }
        }

        public void RaiseOtherProcess()
        {
            IntPtr hwnd = FindWindow(null, AssemblyTitle);//the second instance has no window, thus it cannot be returned by FindWindow()

            ShowWindowAsync(hwnd, SW_SHOW);
            ShowWindowAsync(hwnd, SW_RESTORE);
            SetForegroundWindow(hwnd);
        }

        private void Release()
        {
            if (_owned)
            {
                //If we own the mutex than release it so that

                // other "same" processes can now start.

                _processSync.ReleaseMutex();
                _owned = false;
            }
        }

        #region Implementation of IDisposable
        public void Dispose()
        {
            //release mutex (if necessary) and notify 

            // the garbage collector to ignore the destructor

            Release();
            GC.SuppressFinalize(this);
        }
        #endregion
    }
}